import * as vscode from "vscode";
import { PackageConfig } from "@ap/types/config";
import { BASE_CFG_JSON, getPackageJson } from "@ap/util/packageJson";
import { arenaErrorMsg } from "@ap/util/vscode/errorMsg";
import {
  showErrorMessage,
  showProgress,
  showInformationMessage,
} from "@ap/util/vscode/message";
import { Client } from "./request";
import { auth, nPost, userData } from "@ap/util/request";
import { FolderReader, Scripts } from "./translate";
import {
  ConfigurationItem,
  ConfigurationKey,
} from "@ap/util/vscode/setInsConfig";
import getFilePath from "@ap/util/vscode/getFilePath";
import { tempPath } from "@ap/util/tempPath";
import path from "path";
import { queue, sleep } from "@ap/util/data";
import { OutputChannel, OutputWrapper } from "@ap/util/vscode/output";
import { read, ReadMode } from "@ap/util/fs";
import { getPathAndFileName2Config } from "@ap/util/vscode/getPathAndFileName2Config";
import { isDevelopment } from "./isDevelopment";
import { CreateStatusBar } from "@ap/init";
import { CommandId } from "@ap/command";
import { removeStringValues } from "@ap/util/mapFile/removeStringValues";

function solveIfNotAbsolute(temp: string, base?: string) {
  if (tempPath) {
    return path.isAbsolute(temp) ? temp : path.resolve(base ?? tempPath, temp);
  }
  return temp;
}
interface hmrObj {
  pid: number | undefined;
  stop: () => boolean;
  isPackage?: boolean;
}
const hmr: Record<string, [hmrObj, hmrObj] | null> = {};
export async function startHMR() {
  const buildPath = getFilePath();
  if (!buildPath) {
    showErrorMessage(arenaErrorMsg.OPEN_WORKSPACE);
    return;
  }
  if (hmr[buildPath] === null) {
    showErrorMessage(
      arenaErrorMsg.THE_CURRENT_PROJECT_HMR_SERVER_IS_READY_TO_START_PLEASE_DO_NOT_REPEAT_THE_OPERATION,
    );
    return;
  }
  if (hmr[buildPath]) {
    showErrorMessage(
      arenaErrorMsg.THE_MODULE_HOT_SWAP_SERVER_IS_ALREADY_RUNNING,
    );
    return;
  }
  // 分别获取文件和地图的配置信息。
  const arenaProFileConfig =
    await getPackageJson<PackageConfig["file"]>("file");
  const arenaProMapConfig = await getPackageJson<PackageConfig["map"]>("map");
  const arenaProOutputAndUpdateConfig =
    await getPackageJson<PackageConfig["outputAndUpdate"]>("outputAndUpdate");
  const arenaProNPMPackagesConfig =
    await getPackageJson<PackageConfig["npmPackage"]>("npmPackage");
  // 校验配置信息是否完整，如果不完整则显示错误消息并终止操作。
  if (!arenaProFileConfig || !arenaProMapConfig) {
    showErrorMessage(arenaErrorMsg.PROFILE_AND_MAP_INFORMATION);
    return;
  }
  if (!arenaProFileConfig.typescript) {
    showErrorMessage(arenaErrorMsg.CONFIGURE_TYPESCRIPT_INFORMATION);
    return;
  }
  hmr[buildPath] = null;
  showProgress("正在启动HMR服务器", async (progress) => {
    Scripts.setRootDir(buildPath);
    const outputWrapper = new OutputWrapper(
      OutputChannel.getInstance(),
      "HMR Runtime",
    );
    // 根据配置信息初始化客户端对象，用于后续的上传操作。
    const client = new Client({
      token: auth,
      mapId: arenaProMapConfig.id,
      folderReader: FolderReader.getInstance(),
      ua: vscode.workspace
        .getConfiguration(ConfigurationItem.USER_CENTER_TOOL)
        .get<string>(ConfigurationKey.USER_AGNET),
    });

    const pathAndFileName2Config = await getPathAndFileName2Config(false);
    const outputNameList = removeStringValues(
      arenaProOutputAndUpdateConfig,
      (result) => {
        result.serverName = "_server_" + path.parse(result.name).name;
        result.clientName = "_client_" + path.parse(result.name).name;
        result.serverEntry = path.resolve(
          pathAndFileName2Config?.server.base || "./server",
          result.serverEntry,
        );
        result.clientEntry = path.resolve(
          pathAndFileName2Config?.client.base || "./client",
          result.clientEntry,
        );
      },
    );
    const scripts = Scripts.createScripts({
      server: {
        npmPackages: arenaProNPMPackagesConfig || undefined,
        base: pathAndFileName2Config?.server.base || "./server",
        entry: pathAndFileName2Config?.server.path || "src/App.ts",
        development: !!isDevelopment(true, arenaProFileConfig),
        webpack:
          arenaProFileConfig.typescript.server.webpack ||
          "./server/webpack.config.js",
        output: pathAndFileName2Config?.server.fileName || "_server_bundle.js",
        esbuild: arenaProFileConfig.typescript.server.esbuild || false,
      },
      client: {
        npmPackages: arenaProNPMPackagesConfig || undefined,
        base: pathAndFileName2Config?.client.base || "./client",
        entry: pathAndFileName2Config?.client.path || "src/clientApp.ts",
        development: !!isDevelopment(false, arenaProFileConfig),
        webpack:
          arenaProFileConfig.typescript.client.webpack ||
          "./client/webpack.config.js",
        output: pathAndFileName2Config?.client.fileName || "_client_bundle.js",
        esbuild: arenaProFileConfig.typescript.client.esbuild || false,
      },
      jsUpdate: arenaProFileConfig.typescript.jsUpdate,
      outputNameList,
    });
    console.log("Starting HMR");

    progress.report({ message: "校验完成，正在准备启动..." });

    const serverWp = await scripts.server.setupHmr(
      path.resolve(
        pathAndFileName2Config?.server.base || "./server",
        pathAndFileName2Config?.server.path || "src/App.ts",
      ),
      path.resolve(
        pathAndFileName2Config?.server.base || "./server",
        await scripts.server.getDist(),
        pathAndFileName2Config?.server.fileName || "_server_bundle.js",
      ),
    );
    const clientWp = await scripts.client.setupHmr(
      path.resolve(
        pathAndFileName2Config?.client.base || "./client",
        pathAndFileName2Config?.client.path || "src/clientApp.ts",
      ),
      path.resolve(
        pathAndFileName2Config?.client.base || "./client",
        await scripts.client.getDist(),
        pathAndFileName2Config?.client.fileName || "_client_bundle.js",
      ),
    );

    const upload = async (
      isServer: boolean,
      filePath: string,
      fileName: string,
      time: number,
    ) => {
      return new Promise(async (resolve) => {
        const { READ } = ReadMode;
        const contents = await read(filePath, { mode: READ, raw: true });
        if (!contents) {
          return;
        }
        const res = await client.updateFile(
          isServer ? 0 : 1,
          contents,
          fileName,
          fileName,
          arenaProNPMPackagesConfig,
        );
        resolve(res);
        if (userData && userData.data) {
          nPost({
            url: "https://box3lab-api.fanhat.cn/dao3lab/arenapro_building_count",
            data: {
              type: 2,
              userid: userData.data.userId,
              name: userData.data.nickname,
              mapid: arenaProMapConfig.id,
              buildingTime: ((Date.now() - time) / 1000).toFixed(2) + "s",
            },
          });
        }
      });
    };

    progress.report({ message: "坐和放宽，正在启动..." });

    // 启动服务器
    const serverHmr = await scripts.server.startHmrServer(
      serverWp,
      async (
        filePath: string,
        fileName: string,
        time: number,
      ): Promise<void> => {
        outputWrapper.info("Server changed: " + filePath);
        const result = await upload(true, filePath, fileName, time);
        if (result === true) {
          outputWrapper.info("Server updated！");
        } else {
          outputWrapper.error("Server update failed: " + result);
          OutputChannel.getInstance().show();
        }
      },
      (code: number | null) => {
        if (hmr[buildPath] && hmr[buildPath][0]) {
          hmr[buildPath][0].pid = undefined;
        }
        setHMRToolStatus(buildPath);
      },
    );
    const clientHmr = await scripts.client.startHmrServer(
      clientWp,
      async (
        filePath: string,
        fileName: string,
        time: number,
      ): Promise<void> => {
        outputWrapper.info("Client changed: " + filePath);
        const result = await upload(false, filePath, fileName, time);
        if (result === true) {
          outputWrapper.info("Client updated！");
        } else {
          outputWrapper.error("Client update failed: " + result);
          OutputChannel.getInstance().show();
        }
      },
      (code: number | null) => {
        if (hmr[buildPath] && hmr[buildPath][1]) {
          hmr[buildPath][1].pid = undefined;
        }
        setHMRToolStatus(buildPath);
      },
    );
    hmr[buildPath] = [serverHmr, clientHmr];
    setHMRToolStatus(buildPath);
  });
}

export async function stopHMR(isMsg: boolean = true): Promise<boolean> {
  const buildPath = getFilePath();
  if (!buildPath) {
    showInformationMessage(arenaErrorMsg.OPEN_WORKSPACE);
    return false;
  }
  const pkgPath = path.parse(getFilePath(BASE_CFG_JSON) || "").dir;
  if (!pkgPath) {
    showErrorMessage(arenaErrorMsg.CONFIGURE_PACKAGE_JSON);
    return false;
  }
  if (!hmr[buildPath]) {
    if (isMsg) {
      showErrorMessage(arenaErrorMsg.THE_MODULE_HOT_SWAP_SERVER_IS_NOT_STARTED);
    }
    return false;
  }

  hmr[buildPath].forEach(async (h) => {
    h?.stop();
  });
  delete hmr[buildPath];
  setHMRToolStatus(buildPath);
  return true;
}

function setTooltip(toip: vscode.MarkdownString) {
  toip.isTrusted = true;
  CreateStatusBar.buildHMRToolObj.tooltip = toip;
}

/**
 * 设置HMR工具的状态
 * @param buildPath 可选参数，指定构建路径
 */
export function setHMRToolStatus(buildPath?: string) {
  try {
    // 如果未提供构建路径，则获取默认文件路径
    if (!buildPath) {
      buildPath = getFilePath();
    }

    // 如果构建路径为空，hmr对象不存在，hmr对象为空，或指定构建路径的HMR信息不存在，则重置状态栏
    if (
      !buildPath ||
      !hmr ||
      Object.keys(hmr).length === 0 ||
      !hmr[buildPath]
    ) {
      resetStatusBar();
      return;
    }

    // 获取指定构建路径的HMR项
    const hmrItem = hmr[buildPath];
    if (hmrItem) {
      // 创建并设置工具提示
      const toip = createTooltip(hmrItem);
      setTooltip(toip);
    }
  } catch (error) {
    // 捕获异常并重置状态栏
    console.error("Error in setHMRToolStatus:", error);
    resetStatusBar();
  }
}

/**
 * 重置状态栏的显示
 */
function resetStatusBar() {
  // 重置状态栏项目的背景色和前景色
  CreateStatusBar.buildHMRToolObj.backgroundColor = undefined;
  CreateStatusBar.buildHMRToolObj.color = CreateStatusBar.STATUS_BAR_COLOR;
  // 创建并设置重新启动提示的Markdown字符串
  const toip = new vscode.MarkdownString(
    CreateStatusBar.buildHMRToolObj_reStartText,
    true,
  );
  setTooltip(toip);
}

/**
 * 根据HMR项创建工具提示
 * @param hmrItem HMR项，包含服务端和客户端进程信息
 * @returns 返回格式化的Markdown字符串
 */
function createTooltip(hmrItem: [any, any]): vscode.MarkdownString {
  let backgroundColor: vscode.ThemeColor | undefined;
  let color: string;

  // 根据服务端和客户端进程状态设置背景色和前景色
  if (hmrItem[0]?.pid && hmrItem[1]?.pid) {
    backgroundColor = undefined;
    color = CreateStatusBar.STATUS_SUCCESS_COLOR;
  } else if (
    (hmrItem[0]?.isPackage || hmrItem[1]?.isPackage) &&
    (hmrItem[0]?.pid || hmrItem[1]?.pid)
  ) {
    backgroundColor = undefined;
    color = CreateStatusBar.STATUS_SUCCESS_COLOR;
  } else {
    backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
    color = CreateStatusBar.STATUS_WARN_COLOR;
  }

  // 更新状态栏项目的背景色和前景色
  CreateStatusBar.buildHMRToolObj.backgroundColor = backgroundColor;
  CreateStatusBar.buildHMRToolObj.color = color;

  // 构建并返回包含服务端和客户端进程信息的Markdown字符串
  return new vscode.MarkdownString(
    `服务端进程PID：${hmrItem[0]?.pid || "已关闭/未启动"}\n\n客户端进程PID：${
      hmrItem[1]?.pid || "已关闭/未启动"
    }\n\n---\n` + CreateStatusBar.buildHMRToolObj_stopText,
    true,
  );
}

export async function stopHMRAll() {
  Object.entries(hmr).find(([buildPath, hmrItem]) => {
    hmrItem?.forEach((h) => {
      h?.stop();
    });
    delete hmr[buildPath];
  });
}
